﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Mysoft.QuickCode.Data.Validator
{
    /// <summary>
    /// 实体数据对象属性值合法性校验校验
    /// </summary>
    public sealed class DataValidator
    {
        /// <summary>
        /// 执行实体校验，并返回校验结果
        /// </summary>
        /// <param name="model">要校验的，设置了字段属性的实体</param>
        /// <returns>实体数据校验结果</returns>
        public static ValidationResult Exec(object model)
        {
            DataValidator validator = new DataValidator();
            PropertyInfo[] properties = model.GetType().GetProperties();
            foreach (PropertyInfo p in properties)
            {
                ValidationResult vr = validator.Validate(model, p);
                if (!vr.Result)
                {
                    //校验失败，返回错误信息
                    return vr;
                }
            }
            //校验通过
            return new ValidationResult { Result = true, ErrorMessage = string.Empty };
        }

        #region 属性验证方法

        private ValidationResult Validate(object model, PropertyInfo property)
        {
            object[] attrs = property.GetCustomAttributes(false);
            foreach (object t in attrs)
            {
                ValidationResult vr = null;
                if (t is RequiredAttribute)
                {
                    vr = new RequiredValidate(model, property).Validate();
                }
                else if (t is StringLengthAttribute)
                {
                    vr = new StringLengthValidate(model, property).Validate();
                }
                else if (t is RangeAttribute)
                {
                    vr = new RangeValidate(model, property).Validate();
                }
                else if (t is RegularExpressionAttribute)
                {
                    vr = new RegularExpressionValidate(model, property).Validate();
                }

                //存在校验失败的字段，则返回校验结果
                if (vr != null && !vr.Result)
                {
                    return vr;
                }
            }

            return new ValidationResult { Result = true, ErrorMessage = string.Empty };

        }

        #endregion
    }

    #region 验证器实现

    public abstract class AttributeValidate
    {
        protected object model;
        protected PropertyInfo property;
        protected string DisplayName;

        public AttributeValidate(object model, PropertyInfo property)
        {
            this.model = model;
            this.property = property;

            //提取DisplayName
            RequiredAttribute reqAttr = this.property.GetCustomAttributes(typeof(RequiredAttribute), false).FirstOrDefault() as RequiredAttribute;
            DisplayNameAttribute displayAttr = this.property.GetCustomAttributes(typeof(DisplayNameAttribute), false).FirstOrDefault() as DisplayNameAttribute;
            this.DisplayName = (displayAttr == null) ? property.Name : displayAttr.DisplayName;
        }
        public abstract ValidationResult Validate();
    }

    /// <summary>
    /// 必填字段校验
    /// </summary>
    public class RequiredValidate : AttributeValidate
    {
        public RequiredValidate(object model, PropertyInfo property)
            : base(model, property)
        {
        }

        public override ValidationResult Validate()
        {
            RequiredAttribute attr = this.property.GetCustomAttributes(typeof(RequiredAttribute), false).FirstOrDefault() as RequiredAttribute;
            string errorMessage = string.IsNullOrEmpty(attr.ErrorMessage) ?
                       "{0} 不允许为空！" : attr.ErrorMessage;
            if (!attr.IsValid(this.property.GetValue(model, null)))
            {
                return new ValidationResult
                {
                    Result = false,
                    ErrorMessage = string.Format(errorMessage, this.DisplayName)
                };
            }

            return new ValidationResult() { Result = true, ErrorMessage = string.Empty };
        }
    }

    /// <summary>
    /// 字符串长度校验
    /// </summary>
    public class StringLengthValidate : AttributeValidate
    {
        public StringLengthValidate(object model, PropertyInfo property)
            : base(model, property)
        {
        }

        public override ValidationResult Validate()
        {
            StringLengthAttribute attr = this.property.GetCustomAttributes(typeof(StringLengthAttribute), false).FirstOrDefault() as StringLengthAttribute;
            string errorMessage = string.IsNullOrEmpty(attr.ErrorMessage) ?
                       "{0} 长度不能超过 {1} 字符！" : attr.ErrorMessage;
            if (!attr.IsValid(this.property.GetValue(model, null)))
            {
                return new ValidationResult
                {
                    Result = false,
                    ErrorMessage = string.Format(errorMessage, this.DisplayName, attr.MaximumLength)
                };
            }

            return new ValidationResult() { Result = true, ErrorMessage = string.Empty };
        }
    }

    /// <summary>
    /// 范围数字验证，如：年龄在 1 与 200 之间
    /// </summary>
    public class RangeValidate : AttributeValidate
    {
        public RangeValidate(object model, PropertyInfo property)
            : base(model, property)
        {
        }

        public override ValidationResult Validate()
        {
            RangeAttribute attr = this.property.GetCustomAttributes(typeof(RangeAttribute), false).FirstOrDefault() as RangeAttribute;
            string errorMessage = string.IsNullOrEmpty(attr.ErrorMessage) ?
                       "{0} 必须在 {1} 至 {2} 之间！" : attr.ErrorMessage;
            if (!attr.IsValid(this.property.GetValue(model, null)))
            {
                return new ValidationResult
                {
                    Result = false,
                    ErrorMessage = string.Format(errorMessage, this.DisplayName, attr.Minimum, attr.Maximum)
                };
            }

            return new ValidationResult() { Result = true, ErrorMessage = string.Empty };
        }
    }

    /// <summary>
    /// 正则表达式数据校验
    /// </summary>
    public class RegularExpressionValidate : AttributeValidate
    {
        public RegularExpressionValidate(object model, PropertyInfo property)
            : base(model, property)
        {
        }

        public override ValidationResult Validate()
        {
            RegularExpressionAttribute attr = this.property.GetCustomAttributes(typeof(RegularExpressionAttribute), false).FirstOrDefault() as RegularExpressionAttribute;
            string errorMessage = string.IsNullOrEmpty(attr.ErrorMessage) ?
                       "{0} 格式错误！" : attr.ErrorMessage;
            if (!attr.IsValid(this.property.GetValue(model, null)))
            {
                return new ValidationResult
                {
                    Result = false,
                    ErrorMessage = string.Format(errorMessage, this.DisplayName)
                };
            }

            return new ValidationResult() { Result = true, ErrorMessage = string.Empty };
        }
    }

    #endregion

}
